home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-20 | 12.7 KB | 513 lines | [TEXT/MPCC] |
- /*
- File: DragStuff.c
-
- Contains: Drag Manager handlers and associated routines
-
- Written by: Chris White, Developer Technical Support
-
- Copyright: © 1995 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- 9/28/95 CW First release
-
- */
-
-
- // System includes
- #ifndef __DRAG__
- #include <Drag.h>
- #endif
-
- #ifndef __ERRORS__
- #include <Errors.h>
- #endif
-
- #ifndef __GESTALT__
- #include <Gestalt.h>
- #endif
-
- #ifndef __CODEFRAGMENTS__
- #include <CodeFragments.h>
- #endif
-
- #ifndef __SCRIPT__
- #include <Script.h>
- #endif
-
- #ifndef __RESOURCES__
- #include <Resources.h>
- #endif
-
- #ifndef __STDDEF__
- #include <stddef.h>
- #endif
-
-
-
- // Application includes
- #ifndef __FRAGMENTTOOL__
- #include "FragmentTool.h"
- #endif
-
- #ifndef __PROTOTYPES__
- #include "Prototypes.h"
- #endif
-
-
- #include "Utilities.h"
-
-
-
- static Boolean gHasAcceptableDrag = false;
- static Boolean gHasHilitedList = false;
-
-
-
-
- static Boolean DragItemsAreAcceptable ( DragReference theDrag );
- static Boolean DragIsNotInSourceWindow ( DragReference theDrag );
-
-
- static pascal OSErr DragTracker ( DragTrackingMessage theMessage, WindowRef theWindow,
- void *handlerRefCon, DragReference theDrag );
- static pascal OSErr DragTracker ( DragTrackingMessage theMessage, WindowRef theWindow,
- void *handlerRefCon, DragReference theDrag );
- static pascal OSErr DragReceiver ( WindowRef theWindow, void *handlerRefCon,
- DragReference theDrag );
- static pascal OSErr SendDataProc ( FlavorType theType, void *dragSendRefCon,
- ItemReference theItemRef, DragReference theDragRef );
-
-
-
- //
- // InitDragHandlers creates the UPPs for the Drag Manager
- // callback routines _if_ the Drag Manager is available.
- //
- OSErr InitDragHandlers ( void )
- {
- OSErr theErr = noErr;
-
- if ( gHasDragManager )
- {
- gDragTrackingHandlerUPP = NewDragTrackingHandlerProc ( DragTracker );
- gDragReceiveHandlerUPP = NewDragReceiveHandlerProc ( DragReceiver );
- gDragSendDataProcUPP = NewDragSendDataProc ( SendDataProc );
- }
-
- return theErr;
- }
-
-
-
- //
- // InstallDragHandlers attaches the tracking and receive handlers to
- // one of the application's windows.
- //
- OSErr InstallDragHandlers ( WindowRef theWindow )
- {
- OSErr theErr = noErr;
-
- if ( gHasDragManager )
- {
-
- theErr = InstallTrackingHandler ( gDragTrackingHandlerUPP, theWindow, nil );
-
- if ( theErr == noErr )
- {
- theErr = InstallReceiveHandler ( gDragReceiveHandlerUPP, theWindow, nil );
- if ( theErr )
- (void) RemoveTrackingHandler ( gDragTrackingHandlerUPP, theWindow );
- }
-
- }
-
- return theErr;
- }
-
-
-
- //
- // RemoveDragHandlers removes the tracking and receive handlers from
- // one of the application's windows (usually just prior to disposal).
- //
- void RemoveDragHandlers ( WindowRef theWindow )
- {
- if ( gHasDragManager )
- {
-
- RemoveReceiveHandler ( gDragReceiveHandlerUPP, theWindow );
- RemoveTrackingHandler ( gDragTrackingHandlerUPP, theWindow );
-
- }
-
- return;
- }
-
-
-
- //
- // DragItemsAreAcceptable returns true if the contents (data) of
- // the drag are acceptable. This is called by the tracking and
- // receive handlers.
- //
- static Boolean DragItemsAreAcceptable ( DragReference theDrag )
- {
- OSErr theErr;
- unsigned short totalItems;
- ItemReference itemRef;
- Boolean bAcceptIt;
- OSType currOSType;
- Size flavorDataSize;
-
-
- bAcceptIt = false;
-
-
- // this app can only accept the drag of a single item
- theErr = CountDragItems ( theDrag, &totalItems );
-
- if ( theErr == noErr && totalItems == 1 )
- {
- // get the reference number of the dragged item
- theErr = GetDragItemReferenceNumber ( theDrag, 1, &itemRef );
-
- if ( theErr == noErr )
- {
- // check if the item is one of ours
- flavorDataSize = sizeof ( OSType );
- theErr = GetFlavorData ( theDrag, itemRef, kCreatorCode, &currOSType,
- &flavorDataSize, 0 );
-
- //#if DEBUGGING
- //if ( theErr ) DebugStr ( "\p GetFlavorData returned an error" );
- //#endif
-
- if ( theErr == noErr )
- bAcceptIt = true;
- }
- }
- return bAcceptIt;
- }
-
-
-
- //
- // DragIsNotInSourceWindow returns true if the drag in progress
- // is not in the same window it originated in. This is called by
- // the tracking and receive handlers.
- //
- static Boolean DragIsNotInSourceWindow ( DragReference theDrag )
- {
- DragAttributes currDragFlags;
-
- GetDragAttributes ( theDrag, &currDragFlags );
- return !(currDragFlags & dragInsideSenderWindow);
- }
-
-
-
- //
- // DragTracker is called by the drag manager whenever a drag is
- // over one of the application's windows. Upon entry, the Drag
- // Manager has already set the current port current to ‘theWindow’.
- pascal OSErr DragTracker ( DragTrackingMessage theMessage, WindowRef theWindow,
- void* handlerRefCon, DragReference theDrag )
- {
- RgnHandle tempRgn;
- Boolean mouseInList;
- OSErr err;
-
- err = noErr;
-
- switch ( theMessage )
- {
- case dragTrackingEnterHandler:
-
- // Any initialization for this window handler.
- gHasAcceptableDrag = DragItemsAreAcceptable ( theDrag );
- gHasHilitedList = false;
-
- // Let the drag manager know if we can't accept this drag
- if ( !gHasAcceptableDrag )
- err = dragNotAcceptedErr;
- break;
-
- case dragTrackingEnterWindow:
- case dragTrackingInWindow:
- case dragTrackingLeaveWindow:
-
- // Highlighting of the window during a drag is done
- // here. Do it only if we can accept these items
- // and we're not in the source window...
-
- if ( gHasAcceptableDrag )
- {
- // Unless the mouse is leaving the visible area of the
- // window, check if it's in the window's content region
-
- mouseInList = false;
- if ( theMessage != dragTrackingLeaveWindow )
- {
- if ( DragIsNotInSourceWindow ( theDrag ) )
- {
- Point localPt;
-
- (void) GetDragMouse ( theDrag, &localPt, 0L );
- GlobalToLocal ( &localPt );
- mouseInList = PtInList ( localPt, GetWListRef ( theWindow ) );
- }
- }
-
- // If the mouse is in the list and it isn't hilited...
- if ( mouseInList && !gHasHilitedList )
- {
- Rect nuSpaceRect;
-
- GetListRect ( &nuSpaceRect, GetWListRef ( theWindow ) );
-
- tempRgn = NewRgn ( );
- RectRgn ( tempRgn, &nuSpaceRect );
-
- // ...draw the hilight...
- if ( ShowDragHilite ( theDrag, tempRgn, true ) == noErr )
- // ... and remember it's now hilited
- gHasHilitedList = mouseInList;
-
- DisposeRgn ( tempRgn );
- }
-
- // else if the mouse is not in the list and the window is hilited...
- else if ( !mouseInList && gHasHilitedList )
- // ...erase the hilight...
- if ( HideDragHilite ( theDrag ) == noErr )
- // ...remember that nothing is hilited
- gHasHilitedList = false;
- }
- break;
-
- // do nothing for the leaveHandler message
- case dragTrackingLeaveHandler:
- break;
-
- // let the drag manager know if we didn't recognize the message
- default:
- err = paramErr;
- }
-
- return err;
- }
-
-
-
- //
- // DragReceiver is called by the drag manager whenever an
- // item is dropped on one of the application's windows.
- //
- pascal OSErr DragReceiver ( WindowRef theWindow, void *handlerRefCon, DragReference theDrag )
- {
- #pragma unused (theWindow, handlerRefCon)
-
- Boolean bMove;
- ItemReference itemRef;
- Size dataSize;
- OSErr err = noErr;
- unsigned short numItems, counter;
- tDragData theData;
- int16 mouseDownModifiers, mouseUpModifiers;
-
-
-
- if (!DragItemsAreAcceptable(theDrag) || (gHasHilitedList == false))
- return dragNotAcceptedErr;
-
-
- err = GetDragModifiers ( theDrag, nil, &mouseDownModifiers, &mouseUpModifiers );
- if ( err ) goto CleanupAndBail;
- bMove = !((mouseDownModifiers & optionKey) | (mouseUpModifiers & optionKey));
-
- CountDragItems(theDrag, &numItems);
- for (counter = 1; counter <= numItems; counter++)
- {
- err = GetDragItemReferenceNumber(theDrag, counter, &itemRef);
- if (err != noErr) goto CleanupAndBail;
-
- dataSize = sizeof ( tDragData );
- err = GetFlavorDataSize ( theDrag, itemRef, kCreatorCode, &dataSize );
- if ( dataSize == sizeof ( tDragData ) )
- err = GetFlavorData ( theDrag, itemRef, kCreatorCode, &theData, &dataSize, 0 );
-
-
- // We're going to first remove the drag hilite from here, because
- // not doing so would result in a cleared out list rect, and when
- // we go through the trackingLeaveWindow message up above, the
- // HideDragHilite() call would draw the border again (since it's drawn
- // in XOr mode).
-
- if ( gHasHilitedList )
- {
- if ( HideDragHilite ( theDrag ) == noErr)
- // remember that nothing is hilited
- gHasHilitedList = false;
- }
-
-
- if ( bMove )
- err = MoveWindowFragment ( theData.theWindow, theData.theIndex, theWindow );
- else
- err = CopyWindowFragment ( theData.theWindow, theData.theIndex, theWindow );
- }
-
- CleanupAndBail:
- return err;
- }
-
-
-
- //
- // This is the Drag Manager's SendDataProc. It's called after a successful drag, when
- // the target application wants some data that was promised by the source application.
- //
- pascal OSErr SendDataProc ( FlavorType theType, void* dragSendRefCon,
- ItemReference theItemRef, DragReference theDragRef )
-
- {
- // Gotcha: If we had just dragged out to the Finder, and we had a windowKind of
- // 20, the system would have crashed by now. Why? The Finder uses a windowKind
- // of 20, and thinks this is a drag from one of its windows. It then starts
- // interpreting the window's refCon and inevitably doesn't like what it finds.
- // A windowKind of 20 is now reserved for use by the system.
-
-
- OSErr result = noErr;
- FSSpec locationSpec;
- tHeaderHan theHeader = nil;
- hdrHand theResource = nil;
-
-
-
- // We use the file type for the HFSPromise flavor type
- // and we don't handle any other pomised flavour types.
- if ( theType != kCFragLibraryFileType )
- cantGetFlavorErr;
-
-
- result = CreateTemporaryFile ( &locationSpec );
- if ( result == noErr )
- {
- OSErr theErr;
- int16 theIndex = 0;
- int16 theRef, saveFile;
- WindowRef theWindow;
- ListRef theList;
- tWindowInfoPtr theInfo;
-
- theWindow = (WindowRef) dragSendRefCon;
- theInfo = (tWindowInfoPtr) GetWRefCon ( theWindow );
- theList = GetWListRef ( theWindow );
-
- theHeader = (tHeaderHan) NewHandleClear ( sizeof ( tHeader ) );
- theErr = MemError ( );
- if ( theErr ) goto CleanupAndBail;
-
- (*theHeader)->version = 1; // Current version number
-
- // First, we'll add the content to the file
- while ( GetSelection ( theList, &theIndex ) )
- {
- int16 itemIndex;
-
- itemIndex = GetIndexFromNthWindowItem ( theWindow, theIndex );
- theErr = CopyFragment ( (tHeaderHan) theInfo->dataHandle, &theInfo->fileSpec,
- itemIndex, theHeader, &locationSpec );
- if ( theErr ) goto CleanupAndBail;
- theIndex++;
- }
-
- theResource = (hdrHand) NewHandleClear ( offsetof ( cfrgHeader, arrayStart ) );
- (*theResource)->version = 1; // Current version number
-
- theErr = BuildResource ( (tHeaderHan) theHeader, (Handle) theResource );
- if ( theErr ) goto CleanupAndBail;
-
- saveFile = CurResFile ( );
- theRef = FSpOpenResFile ( &locationSpec, fsRdWrPerm );
- // If the file is already open, it may not be the current resource file
- UseResFile ( theRef );
- AddResource ( (Handle) theResource, kCFragResourceType, kCFragResourceID, "\p" );
- UpdateResFile ( theRef );
- ReleaseResource ( (Handle) theResource );
- CloseResFile ( theRef );
- UseResFile ( saveFile );
-
-
- // Now, set the flavor data of our kCFragLibraryFileType flavor
- // with an FSSpec to the new file.
- result = SetDragItemFlavorData ( theDragRef, theItemRef, theType,
- &locationSpec, sizeof ( FSSpec ), 0L );
-
- }
-
-
- // Any errors? Return a cantGetFlavorErr
- if ( result )
- result = cantGetFlavorErr;
-
- return result;
-
- CleanupAndBail:
-
- // We'll leave the temp file for the system to handle. It
- // could still be useful, if only for debugging purposes.
- if ( theHeader )
- DisposeHandle ( (Handle) theHeader );
-
-
- if ( theResource )
- {
- if ( IsAResource ( (Handle) theResource ) )
- ReleaseResource ( (Handle) theResource );
- else
- DisposeHandle ( (Handle) theResource );
- }
-
- return cantGetFlavorErr;
- }
-
-
-
- //
- // This routine just promises the Drag Manager that we'll create a file
- // if the user drags out to the Finder
- //
- OSErr AddHFSPromise ( DragReference theDrag, ItemReference theItem )
- {
- OSErr theErr;
- PromiseHFSFlavor thePromise;
-
-
- // Here's what we're going to promise to create in our send proc
- thePromise.fileType = kCFragLibraryFileType;
- thePromise.fileCreator = kFourQuestionMarks;
- thePromise.fdFlags = 0;
- thePromise.promisedFlavor = kCFragLibraryFileType;
-
-
- // The promised flavor can be anything, just as long as we add a drag item
- // that has the same type, and set it in our send proc. Failure to do this
- // will cause the zoomback.
-
- theErr = AddDragItemFlavor ( theDrag, theItem, flavorTypePromiseHFS, &thePromise,
- sizeof ( PromiseHFSFlavor ), 0L );
- if ( theErr == noErr )
- // Here's the promised flavor we're going to deliver
- theErr = AddDragItemFlavor ( theDrag, theItem, kCFragLibraryFileType, nil, 0L, 0L );
-
-
- return theErr;
- }
-
-
-
-
-